From 4ca1f7e29f60753621a33215dfa52cec23457f5c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 29 Jul 2018 03:31:36 +0200 Subject: [PATCH] widget: Add GtkWidgetClass:root and :unroot functions They get added whenever a widget gets added into a hierarchy with a root widget. --- gtk/gtkwidget.c | 71 +++++++++++++++++++++++++++++++++++++++--- gtk/gtkwidget.h | 5 +++ gtk/gtkwidgetprivate.h | 5 +++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 4002e2ba12..23ac98c154 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -602,6 +602,8 @@ static void gtk_widget_real_move_focus (GtkWidget GtkDirectionType direction); static gboolean gtk_widget_real_keynav_failed (GtkWidget *widget, GtkDirectionType direction); +static void gtk_widget_root (GtkWidget *widget); +static void gtk_widget_unroot (GtkWidget *widget); #ifdef G_ENABLE_CONSISTENCY_CHECKS static void gtk_widget_verify_invariants (GtkWidget *widget); static void gtk_widget_push_verify_invariants (GtkWidget *widget); @@ -853,6 +855,18 @@ gtk_widget_real_grab_notify (GtkWidget *widget, } } +static void +gtk_widget_real_root (GtkWidget *widget) +{ + gtk_widget_forall (widget, (GtkCallback) gtk_widget_root, NULL); +} + +static void +gtk_widget_real_unroot (GtkWidget *widget) +{ + gtk_widget_forall (widget, (GtkCallback) gtk_widget_unroot, NULL); +} + static void gtk_widget_class_init (GtkWidgetClass *klass) { @@ -899,6 +913,8 @@ gtk_widget_class_init (GtkWidgetClass *klass) klass->unmap = gtk_widget_real_unmap; klass->realize = gtk_widget_real_realize; klass->unrealize = gtk_widget_real_unrealize; + klass->root = gtk_widget_real_root; + klass->unroot = gtk_widget_real_unroot; klass->size_allocate = gtk_widget_real_size_allocate; klass->get_request_mode = gtk_widget_real_get_request_mode; klass->measure = gtk_widget_real_measure; @@ -2868,6 +2884,9 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class) gtk_css_node_set_visible (priv->cssnode, priv->visible); /* need to set correct type here, and only class has the correct type here */ gtk_css_node_set_widget_type (priv->cssnode, G_TYPE_FROM_CLASS (g_class)); + + if (g_type_is_a (G_TYPE_FROM_CLASS (g_class), GTK_TYPE_ROOT)) + priv->root = (GtkRoot *) widget; } @@ -2995,6 +3014,42 @@ gtk_widget_new (GType type, return widget; } +static void +gtk_widget_root (GtkWidget *widget) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + /* roots are rooted by default */ + if (GTK_IS_ROOT (widget)) + return; + + g_assert (priv->root == NULL); + g_assert (!priv->realized); + g_assert (priv->parent); + g_assert (priv->parent->priv->root); + + priv->root = priv->parent->priv->root; + + GTK_WIDGET_GET_CLASS (widget)->root (widget); +} + +static void +gtk_widget_unroot (GtkWidget *widget) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + /* roots are rooted by default and cannot be unrooted */ + if (GTK_IS_ROOT (widget)) + return; + + g_assert (priv->root); + g_assert (!priv->realized); + + GTK_WIDGET_GET_CLASS (widget)->unroot (widget); + + priv->root = NULL; +} + /** * gtk_widget_unparent: * @widget: a #GtkWidget @@ -3046,6 +3101,9 @@ gtk_widget_unparent (GtkWidget *widget) if (_gtk_widget_get_realized (widget)) gtk_widget_unrealize (widget); + if (priv->root) + gtk_widget_unroot (widget); + /* If we are unanchoring the child, we save around the toplevel * to emit hierarchy changed */ @@ -3103,10 +3161,9 @@ gtk_widget_unparent (GtkWidget *widget) gtk_list_list_model_item_removed (old_parent->priv->children_observer, old_prev_sibling); if (toplevel) - { - _gtk_widget_propagate_hierarchy_changed (widget, toplevel); - g_object_unref (toplevel); - } + _gtk_widget_propagate_hierarchy_changed (widget, toplevel); + + g_clear_object (&toplevel); /* Now that the parent pointer is nullified and the hierarchy-changed * already passed, go ahead and unset the parent window, if we are unparenting @@ -6591,7 +6648,11 @@ gtk_widget_reposition_after (GtkWidget *widget, } if (priv->parent->priv->anchored && prev_parent == NULL) - _gtk_widget_propagate_hierarchy_changed (widget, NULL); + { + _gtk_widget_propagate_hierarchy_changed (widget, NULL); + } + if (parent->priv->root && priv->root == NULL) + gtk_widget_root (widget); if (prev_parent == NULL) g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_PARENT]); diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 9b89f70246..7afc676351 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -152,6 +152,9 @@ struct _GtkWidget * widget is destroyed, which means that gtk_widget_unrealize() has * been called or the widget has been unmapped (that is, it is going * to be hidden). + * @root: Called when the widget gets added to a #GtkRoot widget. + * @unroot: Called when the widget is about to be removed from its + * #GtkRoot widget. * @size_allocate: Signal emitted to get the widget allocation. * @state_flags_changed: Signal emitted when the widget state changes, * see gtk_widget_get_state_flags(). @@ -247,6 +250,8 @@ struct _GtkWidgetClass void (* unmap) (GtkWidget *widget); void (* realize) (GtkWidget *widget); void (* unrealize) (GtkWidget *widget); + void (* root) (GtkWidget *widget); + void (* unroot) (GtkWidget *widget); void (* size_allocate) (GtkWidget *widget, int width, int height, diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index cdfe98b9be..acc8eca031 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -124,6 +124,11 @@ struct _GtkWidgetPrivate */ gchar *name; + /* The root this widget belongs to or %NULL if widget is not + * rooted or is a #GtkRoot itself. + */ + GtkRoot *root; + /* The list of attached windows to this widget. * We keep a list in order to call reset_style to all of them, * recursively. -- 2.30.2